﻿Public Class TMyConnectList
    Private _List As New List(Of TMyConnectInfo)
    Private _ListFile As String
    Private Const LIST_FILE_NAME As String = "connectlist.txt"
    Private Const DECRIPTED_FILE_NAME As String = "connectlist.dec.txt"
    Private ReadOnly Property Password() As String
        Get
            Return "gokgfweGeraG#grel;l$3"
        End Get
    End Property
    Public ReadOnly Property DecriptedListFile() As String
        Get
            Return IncludeTrailingPathDelimiter(System.AppDomain.CurrentDomain.BaseDirectory) & DECRIPTED_FILE_NAME
        End Get
    End Property
    Public ReadOnly Property ListFile() As String
        Get
            Return IncludeTrailingPathDelimiter(System.AppDomain.CurrentDomain.BaseDirectory) & LIST_FILE_NAME
        End Get
    End Property

    Private Function IncludeTrailingPathDelimiter(ByVal APath As String) As String
        If Left(APath, 1) = "\" Then
            Return APath
        Else
            Return APath & "\"
        End If
    End Function

    Public Sub Up(ByVal AIndex As Integer)
        If AIndex <= 0 Then
            Return
        End If
        _List.Insert(AIndex - 1, _List(AIndex))
        _List.RemoveAt(AIndex + 1)
        Me.Save()
    End Sub

    Public Sub Down(ByVal AIndex As Integer)
        If AIndex >= _List.Count - 1 Then
            Return
        End If
        _List.Insert(AIndex + 2, _List(AIndex))
        _List.RemoveAt(AIndex)
        Me.Save()
    End Sub

    Public Sub DeleteItem(ByVal AIndex As Integer)
        _List.RemoveAt(AIndex)
        Save()
    End Sub
    Public Sub New()
        Load()
    End Sub

    Public Sub AddItem(ByVal AUserName As String, ByVal APassword As String, ByVal ADatabaseName As String, ByVal AHostName As String)
        Dim item As New TMyConnectInfo
        item.UserName = AUserName
        item.Password = APassword
        item.DatabaseName = ADatabaseName
        item.HostName = AHostName
        Dim blnAdd As Boolean = True
        For i As Integer = 0 To _List.Count - 1
            If _List(i).UserName = AUserName AndAlso _List(i).Password = APassword AndAlso _List(i).DatabaseName = ADatabaseName AndAlso _List(i).HostName = AHostName Then
                blnAdd = False
            End If
        Next
        If blnAdd Then
            _List.Add(item)
        End If
    End Sub

    Public Sub Save()
        Dim sw As New System.IO.StreamWriter(Me.DecriptedListFile, False, System.Text.Encoding.UTF8)
        Try
            Try
                For i As Integer = 0 To _List.Count - 1
                    sw.WriteLine(_List(i).UserName & vbTab & _List(i).Password & vbTab & _List(i).DatabaseName & vbTab & _List(i).HostName)
                Next
            Finally
                sw.Flush()
                sw.Close()
            End Try
            EncryptFile(Me.DecriptedListFile, Me.ListFile, Me.Password)
        Finally
            System.IO.File.Delete(Me.DecriptedListFile)
        End Try
    End Sub

    Public Sub Load()
        _List.Clear()
        If Not System.IO.File.Exists(ListFile) Then
            Return
        End If
        DecryptFile(ListFile, DecriptedListFile, Me.Password)
        Try
            Dim sr As New System.IO.StreamReader(Me.DecriptedListFile, System.Text.Encoding.UTF8)
            Try
                While sr.Peek() > -1
                    Dim item As New TMyConnectInfo
                    Dim sTmp As String() = Split(sr.ReadLine, vbTab)
                    item.UserName = sTmp(0)
                    item.Password = sTmp(1)
                    item.DatabaseName = sTmp(2)
                    item.HostName = sTmp(3)
                    _List.Add(item)
                End While
            Finally
                sr.Close()
            End Try
            EncryptFile(DecriptedListFile, ListFile, Me.Password)
        Finally
            System.IO.File.Delete(DecriptedListFile)
        End Try
    End Sub

    Public ReadOnly Property Count() As Integer
        Get
            Return _List.Count
        End Get
    End Property

    Default Public ReadOnly Property Items(ByVal Index As Integer) As TMyConnectInfo
        Get
            Return _List(Index)
        End Get
    End Property

    ''' <summary>
    ''' パスワードから共有キーと初期化ベクタを生成する
    ''' </summary>
    ''' <param name="password">基になるパスワード</param>
    ''' <param name="keySize">共有キーのサイズ（ビット）</param>
    ''' <param name="key">作成された共有キー</param>
    ''' <param name="blockSize">初期化ベクタのサイズ（ビット）</param>
    ''' <param name="iv">作成された初期化ベクタ</param>
    Private Shared Sub GenerateKeyFromPassword(ByVal password As String, _
                                               ByVal keySize As Integer, _
                                               ByRef key As Byte(), _
                                               ByVal blockSize As Integer, _
                                               ByRef iv As Byte())
        'パスワードから共有キーと初期化ベクタを作成する
        'saltを決める
        Dim salt As Byte() = System.Text.Encoding.UTF8.GetBytes("lkj$wf%endfwR#Fwe~sfd(aln/?kAW#")
        'Rfc2898DeriveBytesオブジェクトを作成する
        Dim deriveBytes As New System.Security.Cryptography.Rfc2898DeriveBytes( _
            password, salt)
        '.NET Framework 1.1以下の時は、PasswordDeriveBytesを使用する
        'Dim deriveBytes As New System.Security.Cryptography.PasswordDeriveBytes( _
        '    password, salt)
        '反復処理回数を指定する デフォルトで1000回
        deriveBytes.IterationCount = 1000

        '共有キーと初期化ベクタを生成する
        key = deriveBytes.GetBytes(keySize \ 8)
        iv = deriveBytes.GetBytes(blockSize \ 8)
    End Sub

    ''' <summary>
    ''' ファイルを暗号化する
    ''' </summary>
    ''' <param name="sourceFile">暗号化するファイルパス</param>
    ''' <param name="destFile">暗号化されたデータを保存するファイルパス</param>
    ''' <param name="password">暗号化に使用するパスワード</param>
    Public Shared Sub EncryptFile(ByVal sourceFile As String, _
                                  ByVal destFile As String, _
                                  ByVal password As String)
        Dim rijndael As New System.Security.Cryptography.RijndaelManaged()

        'パスワードから共有キーと初期化ベクタを作成
        Dim key As Byte() = Nothing, iv As Byte() = Nothing
        GenerateKeyFromPassword(password, rijndael.KeySize, key, rijndael.BlockSize, iv)
        rijndael.Key = key
        rijndael.IV = iv

        '以下、前のコードと同じ
        Dim outFs As New System.IO.FileStream( _
            destFile, System.IO.FileMode.Create, System.IO.FileAccess.Write)
        Dim encryptor As System.Security.Cryptography.ICryptoTransform = _
            rijndael.CreateEncryptor()
        Dim cryptStrm As New System.Security.Cryptography.CryptoStream( _
            outFs, encryptor, System.Security.Cryptography.CryptoStreamMode.Write)

        Dim inFs As New System.IO.FileStream( _
            sourceFile, System.IO.FileMode.Open, System.IO.FileAccess.Read)
        Dim bs As Byte() = New Byte(1023) {}
        Dim readLen As Integer
        While True
            readLen = inFs.Read(bs, 0, bs.Length)
            If readLen = 0 Then
                Exit While
            End If
            cryptStrm.Write(bs, 0, readLen)
        End While

        inFs.Close()
        cryptStrm.Close()
        encryptor.Dispose()
        outFs.Close()
    End Sub

    ''' <summary>
    ''' ファイルを復号化する
    ''' </summary>
    ''' <param name="sourceFile">復号化するファイルパス</param>
    ''' <param name="destFile">復号化されたデータを保存するファイルパス</param>
    ''' <param name="password">暗号化に使用したパスワード</param>
    Public Shared Sub DecryptFile(ByVal sourceFile As String, _
                                  ByVal destFile As String, _
                                  ByVal password As String)
        Dim rijndael As New System.Security.Cryptography.RijndaelManaged()

        'パスワードから共有キーと初期化ベクタを作成
        Dim key As Byte() = Nothing, iv As Byte() = Nothing
        GenerateKeyFromPassword(password, rijndael.KeySize, key, rijndael.BlockSize, iv)
        rijndael.Key = key
        rijndael.IV = iv

        '以下、前のコードと同じ
        Dim inFs As New System.IO.FileStream( _
            sourceFile, System.IO.FileMode.Open, System.IO.FileAccess.Read)
        Dim decryptor As System.Security.Cryptography.ICryptoTransform = _
            rijndael.CreateDecryptor()
        Dim cryptStrm As New System.Security.Cryptography.CryptoStream( _
            inFs, decryptor, System.Security.Cryptography.CryptoStreamMode.Read)

        Dim outFs As New System.IO.FileStream( _
            destFile, System.IO.FileMode.Create, System.IO.FileAccess.Write)
        Dim bs As Byte() = New Byte(1023) {}
        Dim readLen As Integer
        While True
            readLen = cryptStrm.Read(bs, 0, bs.Length)
            If readLen = 0 Then
                Exit While
            End If
            outFs.Write(bs, 0, readLen)
        End While

        outFs.Close()
        cryptStrm.Close()
        decryptor.Dispose()
        inFs.Close()
    End Sub
End Class
